﻿
// BresenHamView.cpp: CBresenHamView 类的实现
//

#include "pch.h"
#include "framework.h"
// SHARED_HANDLERS 可以在实现预览、缩略图和搜索筛选器句柄的
// ATL 项目中进行定义，并允许与该项目共享文档代码。
#ifndef SHARED_HANDLERS
#include "BresenHam.h"
#endif

#include "BresenHamDoc.h"
#include "BresenHamView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CBresenHamView

IMPLEMENT_DYNCREATE(CBresenHamView, CView)

BEGIN_MESSAGE_MAP(CBresenHamView, CView)
	// 标准打印命令
	ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView::OnFilePrintPreview)
	ON_WM_LBUTTONDOWN()
//	ON_WM_MOVE()
	ON_WM_MOUSEMOVE()
END_MESSAGE_MAP()

// CBresenHamView 构造/析构

CBresenHamView::CBresenHamView() noexcept
{
	numOfPoints = 0;
}

CBresenHamView::~CBresenHamView()
{
}

BOOL CBresenHamView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: 在此处通过修改
	//  CREATESTRUCT cs 来修改窗口类或样式

	return CView::PreCreateWindow(cs);
}

// CBresenHamView 绘图

/*
* 在顶点处绘制一个圆形
*/
void CBresenHamView::DrawPoint(CDC * pDC, CPoint2D& point)
{
	CPen pen(PS_SOLID, 5, RGB(point.color.red, point.color.green, point.color.blue));

	pDC->SelectObject(&pen);

	pDC->Ellipse(point.x - 5, point.y - 5, point.x + 5, point.y + 5);
}

void CBresenHamView::DrawLine(CDC * pDC, CPoint2D p0, CPoint2D p1)
{
	// 这一步的目的是确保p0永远在p1的左边
	// 进而可以限制直线的角度在-90度到90度之间
	if (p0.x > p1.x)
	{
		CPoint2D temp = p0;
		p0 = p1;
		p1 = temp;
	}

	// 计算直线斜率
	float slope = float(p1.y - p0.y) / float(p1.x - p0.x);

	// 根据斜率大于等于1、大于等于0小于1、大于等于-1小于0、小于-1划分为四种情况
	if (slope >= 1)
		DrawLineSlopeMoreThanPosi1(pDC, slope, p0, p1);
	else if (slope >= 0 && slope < 1)
		DrawLineSlopeBetween0ToPosi1(pDC, slope, p0, p1);
	else if (slope >= -1 && slope < 0)
		DrawLineSlopeBetweenNagt1To0(pDC, slope, p0, p1);
	else
		DrawLineSlopeLessThanNagt1(pDC, slope, p0, p1);
}

/*
* 斜率大于等于1时，y为主位移方向
*/
void CBresenHamView::DrawLineSlopeMoreThanPosi1(CDC * pDC, float slope, CPoint2D & p0, CPoint2D & p1)
{
	CPoint2D temp = p0;
	
	float xReal = p0.x;			// 代表根据斜率算出来的x坐标
	float xStep = 1 / slope;	// y方向每增加1，x方向固定增加的真实距离

	// 遍历y主位移方向
	for (int i = 1, yDist = p1.y - p0.y; i < yDist; ++i)
	{
		// 每次y方向都固定加1
		temp.y += 1;

		// xReal固定增加xStep
		xReal += xStep;

		if (xReal - temp.x >= 0.5)	// 如果x方向增加xStep更加靠近下一个像素
			temp.x = ceil(xReal);	// 则xReal向上取整
		else
			temp.x = floor(xReal);  // 否则则向下取整

		CalRGB(i, yDist, p0.color, p1.color, temp.color);	// 根据当前步数与总步数的比值计算RGB值

		// 使用SetPixelV()函数画点
		pDC->SetPixelV(temp.x, temp.y, RGB(temp.color.red, temp.color.green, temp.color.blue));
	}
}

/*
* 斜率大于等于0小于1时，x为主位移方向
*/
void CBresenHamView::DrawLineSlopeBetween0ToPosi1(CDC * pDC, float slope, CPoint2D & p0, CPoint2D & p1)
{
	CPoint2D temp = p0;

	float yReal = p0.y;
	float yStep = 1 * slope;

	for (int i = 1, xDist = p1.x - p0.x; i < xDist; ++i)
	{
		temp.x += 1;

		yReal += yStep;

		if (yReal - temp.y >= 0.5)
			temp.y = ceil(yReal);
		else
			temp.y = floor(yReal);

		CalRGB(i, xDist, p0.color, p1.color, temp.color);

		pDC->SetPixelV(temp.x, temp.y, RGB(temp.color.red, temp.color.green, temp.color.blue));
	}
}

/*
* 斜率大于等于-1小于0时，x为主位移方向
*/
void CBresenHamView::DrawLineSlopeBetweenNagt1To0(CDC * pDC, float slope, CPoint2D & p0, CPoint2D & p1)
{
	CPoint2D temp = p0;

	float yReal = p0.y;
	float yStep = 1 * slope;

	for (int i = 1, xDist = p1.x - p0.x; i < xDist; ++i)
	{
		temp.x += 1;

		yReal += yStep;

		if (yReal - temp.y >= -0.5)
			temp.y = floor(yReal);
		else
			temp.y = ceil(yReal);

		CalRGB(i, xDist, p0.color, p1.color, temp.color);

		pDC->SetPixelV(temp.x, temp.y, RGB(temp.color.red, temp.color.green, temp.color.blue));
	}
}

/*
* 斜率小于-1时，y为主位移方向
*/
void CBresenHamView::DrawLineSlopeLessThanNagt1(CDC * pDC, float slope, CPoint2D & p0, CPoint2D & p1)
{
	CPoint2D temp = p0;

	float xReal = p0.x;
	float xStep = 1 / slope;

	for (int i = 1, yDist = p0.y - p1.y; i < yDist; ++i)
	{
		temp.y -= 1;

		xReal -= xStep;

		if (xReal - temp.x >= 0.5)
			temp.x = ceil(xReal);
		else
			temp.x = floor(xReal);

		CalRGB(i, yDist, p0.color, p1.color, temp.color);

		pDC->SetPixelV(temp.x, temp.y, RGB(temp.color.red, temp.color.green, temp.color.blue));
	}
}

/*
* 根据当前步数与总步数的比值计算RGB值
*/
void CBresenHamView::CalRGB(int x, int xDist, CRGB & color0, CRGB & color1, CRGB & currColor)
{
	double ratio = double(x) / double(xDist);

	int r = color0.red - (color0.red - color1.red) * ratio;
	int g = color0.green - (color0.green - color1.green) * ratio;
	int b = color0.blue - (color0.blue - color1.blue) * ratio;

	currColor.red = r;
	currColor.green = g;
	currColor.blue = b;
}

void CBresenHamView::OnDraw(CDC* /*pDC*/)
{
	CBresenHamDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO: 在此处为本机数据添加绘制代码
}


// CBresenHamView 打印

BOOL CBresenHamView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// 默认准备
	return DoPreparePrinting(pInfo);
}

void CBresenHamView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: 添加额外的打印前进行的初始化过程
}

void CBresenHamView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: 添加打印后进行的清理过程
}


// CBresenHamView 诊断

#ifdef _DEBUG
void CBresenHamView::AssertValid() const
{
	CView::AssertValid();
}

void CBresenHamView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

CBresenHamDoc* CBresenHamView::GetDocument() const // 非调试版本是内联的
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CBresenHamDoc)));
	return (CBresenHamDoc*)m_pDocument;
}
#endif //_DEBUG


// CBresenHamView 消息处理程序

/*
* 鼠标左键按下的消息响应函数，用以确定三角形的三个顶点
*/
void CBresenHamView::OnLButtonDown(UINT nFlags, CPoint point)
{
	CDC* pDC = GetDC();

	switch (numOfPoints)
	{
	case 0:
		points[0] = CPoint2D(point, 255, 0, 0);		// 第一个顶点设置为红色
		DrawPoint(pDC, points[0]);
		break;
	case 1:
		points[1] = CPoint2D(point, 0, 255, 0);		// 第二个顶点设置为蓝色
		DrawPoint(pDC, points[1]);
		DrawLine(pDC, points[0], points[1]);
		break;
	case 2:
		points[2] = CPoint2D(point, 0, 0, 255);		// 第三个顶点设置为蓝色
		DrawPoint(pDC, points[2]);
		DrawLine(pDC, points[1], points[2]);
		break;
	default:
		break;
	}

	numOfPoints++;

	pDC->DeleteDC();
	CView::OnLButtonDown(nFlags, point);
}


//void CBresenHamView::OnMove(int x, int y)
//{
//	CView::OnMove(x, y);
//		
//}


void CBresenHamView::OnMouseMove(UINT nFlags, CPoint point)
{
	if (numOfPoints < 3)
		return;
	int xDist = abs(point.x - points[0].x);
	int yDist = abs(point.y - points[0].y);

	if (xDist < 10 && yDist < 10) 
	{
		CDC* pDC = GetDC();
		DrawLine(pDC, points[0], points[2]);

		pDC->DeleteDC();
	}

	CView::OnMouseMove(nFlags, point);
}
